<div class="tmd-doc">
<h1 class="tmd-header-1">
Value Conversion, Assignment and Comparison Rules in Go
</h1>
<p></p>
<div class="tmd-usual">
This article will list all the value comparison, conversion and comparison rules in Go. Please note that type parameter types (used frequently in custom generics) are deliberately ignored in the descriptions of conversion, assignability and comparison rules. In other words, this book doesn't consider the situations in which <a href="https://go101.org/generics/101.html">custom generics</a> are involved.
</div>
<p></p>
<p></p>
<h3 id="conversion" class="tmd-header-3">
Value Conversion Rules
</h3>
<p></p>
<p></p>
<div class="tmd-usual">
In Go, if a value <code class="tmd-code-span">v</code> can be explicitly converted to type <code class="tmd-code-span">T</code>, the conversion can be represented as the form <code class="tmd-code-span">(T)(v)</code>. For most cases, in particular <code class="tmd-code-span">T</code> is a type name (an identifier), the form can be simplified to <code class="tmd-code-span">T(v)</code>.
</div>
<p></p>
<div class="tmd-usual">
One fact we should know is, when it says a value <code class="tmd-code-span">x</code> can be implicitly converted to a type <code class="tmd-code-span">T</code>, then it means <code class="tmd-code-span">x</code> can also be explicitly converted to type <code class="tmd-code-span">T</code>.
</div>
<p></p>
<h4 class="tmd-header-4">
1. the apparent conversion rule
</h4>
<p></p>
<div class="tmd-usual well">
If two types denote the identical type, then their values can be <span class="tmd-bold">implicitly</span> converted to either type of the two.
</div>
<p></p>
<div class="tmd-usual">
For example,
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
values of type <code class="tmd-code-span">byte</code> and <code class="tmd-code-span">uint8</code> can be converted to each other.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
values of type <code class="tmd-code-span">rune</code> and <code class="tmd-code-span">int32</code> can be converted to each other.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
values of type <code class="tmd-code-span">[]byte</code> and <code class="tmd-code-span">[]uint8</code> can be converted to each other.
</div>
</li>
</ul>
<p></p>
<div class="tmd-usual">
Nothing more to explain about this rule, whether you think this case involves conversions or not.
</div>
<p></p>
<h4 id="conversion-rule-underlying-types" class="tmd-header-4">
2. underlying type related conversion rules
</h4>
<p></p>
<div class="tmd-base well">
<div class="tmd-usual">
Given a non-interface value <code class="tmd-code-span">x</code> and a non-interface type <code class="tmd-code-span">T</code>, assume the type of <code class="tmd-code-span">x</code> is <code class="tmd-code-span">Tx</code>,
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
if <code class="tmd-code-span">Tx</code> and <code class="tmd-code-span">T</code> share the same <a href="type-system-overview.html#underlying-type">underlying type</a> (ignoring struct tags), then <code class="tmd-code-span">x</code> can be explicitly converted to <code class="tmd-code-span">T</code>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
if either <code class="tmd-code-span">Tx</code> or <code class="tmd-code-span">T</code> is a <a href="type-system-overview.html#named-type">unnamed type</a> and their underlying types are identical (considering struct tags), then <code class="tmd-code-span">x</code> can be <span class="tmd-bold">implicitly</span> converted to <code class="tmd-code-span">T</code>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
if <code class="tmd-code-span">Tx</code> and <code class="tmd-code-span">T</code> have different underlying types, but both <code class="tmd-code-span">Tx</code> and <code class="tmd-code-span">T</code> are unnamed pointer types and their base types share the same underlying type (ignoring struct tags), then <code class="tmd-code-span">x</code> can be explicitly converted to <code class="tmd-code-span">T</code>.
</div>
</li>
</ul>
</div>
<p></p>
<p></p>
<div class="tmd-usual">
<span class="tmd-italic">(Note, the two <span class="tmd-bold">ignoring struct tags</span> occurrences have taken effect since Go 1.8.)</span>
</div>
<p></p>
<div class="tmd-usual">
An example:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

func main() {
	// []int, IntSlice and MySlice share
	// the same underlying type: []int
	type IntSlice []int
	type MySlice  []int
	type Foo = struct{n int `foo`}
	type Bar = struct{n int `bar`}

	var s  = []int{}
	var is = IntSlice{}
	var ms = MySlice{}
	var x map[Bar]Foo
	var y map[Foo]Bar

	// The two implicit conversions both doesn't work.
	/*
	is = ms // error
	ms = is // error
	*/

	// Must use explicit conversions here.
	is = IntSlice(ms)
	ms = MySlice(is)
	x = map[Bar]Foo(y)
	y = map[Foo]Bar(x)

	// Implicit conversions are okay here.
	s = is
	is = s
	s = ms
	ms = s
}
</code></pre>
<p></p>
<div class="tmd-usual">
Pointer related conversion example:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

func main() {
	type MyInt int
	type IntPtr *int
	type MyIntPtr *MyInt

	var pi = new(int)  // the type of pi is *int
	// ip and pi have the same underlying type,
	// and the type of pi is unnamed, so
	// the implicit conversion works.
	var ip IntPtr = pi

	// var _ *MyInt = pi // can't convert implicitly
	var _ = (*MyInt)(pi) // ok, must explicitly

	// Values of *int can't be converted to MyIntPtr
	// directly, but can indirectly.
	/*
	var _ MyIntPtr = pi  // can't convert implicitly
	var _ = MyIntPtr(pi) // can't convert explicitly
	*/
	var _ MyIntPtr = (*MyInt)(pi)  // ok
	var _ = MyIntPtr((*MyInt)(pi)) // ok

	// Values of IntPtr can't be converted to
	// MyIntPtr directly, but can indirectly.
	/*
	var _ MyIntPtr = ip  // can't convert implicitly
	var _ = MyIntPtr(ip) // can't convert explicitly
	*/
	var _ MyIntPtr = (*MyInt)((*int)(ip))  // ok
	var _ = MyIntPtr((*MyInt)((*int)(ip))) // ok
}
</code></pre>
<p></p>
<h4 class="tmd-header-4">
3. channel specific conversion rule
</h4>
<p></p>
<div class="tmd-usual well">
Given a channel value <code class="tmd-code-span">x</code>, assume its type <code class="tmd-code-span">Tx</code> is a bidirectional channel type, <code class="tmd-code-span">T</code> is also a channel type (bidirectional or not). If <code class="tmd-code-span">Tx</code> and <code class="tmd-code-span">T</code> have the identical element type, and either <code class="tmd-code-span">Tx</code> or <code class="tmd-code-span">T</code> is an unnamed type, then <code class="tmd-code-span">x</code> can be <span class="tmd-bold">implicitly</span> converted to <code class="tmd-code-span">T</code>.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Example:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

func main() {
	type C chan string
	type C1 chan&lt;- string
	type C2 &lt;-chan string

	var ca C
	var cb chan string

	cb = ca // ok, same underlying type
	ca = cb // ok, same underlying type

	// The 4 lines compile okay for this 3rd rule.
	var _, _ chan&lt;- string = ca, cb // ok
	var _, _ &lt;-chan string = ca, cb // ok
	var _ C1 = cb                   // ok
	var _ C2 = cb                   // ok

	// Values of C can't be converted
	// to C1 and C2 directly.
	/*
	var _ = C1(ca) // compile error
	var _ = C2(ca) // compile error
	*/

	// Values of C can be converted
	// to C1 and C2 indirectly.
	var _ = C1((chan&lt;- string)(ca)) // ok
	var _ = C2((&lt;-chan string)(ca)) // ok
	var _ C1 = (chan&lt;- string)(ca)  // ok
	var _ C2 = (&lt;-chan string)(ca)  // ok
}
</code></pre>
<p></p>
<h4 id="conversion-rule-implementation" class="tmd-header-4">
4. interface implementation related conversion rules
</h4>
<p></p>
<div class="tmd-base well">
<div class="tmd-usual">
Given a value <code class="tmd-code-span">x</code> and an interface type <code class="tmd-code-span">I</code>, if the type (or the default type) of <code class="tmd-code-span">x</code> is <code class="tmd-code-span">Tx</code> and <code class="tmd-code-span">Tx</code> implements <code class="tmd-code-span">I</code>, then <code class="tmd-code-span">x</code> can be <span class="tmd-bold">implicitly</span> converted to type <code class="tmd-code-span">I</code>. The conversion result is an interface value (of type <code class="tmd-code-span">I</code>), which boxes
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
a copy of <code class="tmd-code-span">x</code>, if <code class="tmd-code-span">Tx</code> is a non-interface type;
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
a copy of the dynamic value of <code class="tmd-code-span">x</code>, if <code class="tmd-code-span">Tx</code> is an interface type.
</div>
</li>
</ul>
</div>
<p></p>
<div class="tmd-usual">
Please read <a href="interface.html">interfaces in Go</a> for details and examples.
</div>
<p></p>
<p></p>
<h4 class="tmd-header-4">
5. untyped value conversion rule
</h4>
<p></p>
<div class="tmd-usual well">
An untyped value can be <span class="tmd-bold">implicitly</span> converted to type <code class="tmd-code-span">T</code>, if the untyped value can represent as values of type <code class="tmd-code-span">T</code>.
</div>
<p></p>
<div class="tmd-usual">
Example:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

func main() {
	var _ []int = nil
	var _ map[string]int = nil
	var _ chan string = nil
	var _ func()() = nil
	var _ *bool = nil
	var _ interface{} = nil

	var _ int = 123.0
	var _ float64 = 123
	var _ int32 = 1.23e2
	var _ int8 = 1 + 0i
}
</code></pre>
<p></p>
<h4 class="tmd-header-4">
6. constants conversion rule
</h4>
<p></p>
<div class="tmd-usual">
<span class="tmd-italic">(This rule is some overlapped with the last one.)</span>
</div>
<p></p>
<div class="tmd-usual">
Generally, converting a constant still yields a constant as result (except that the target type is not a basic type).
</div>
<p></p>
<div class="tmd-usual well">
Given a constant value <code class="tmd-code-span">x</code> and a basic type <code class="tmd-code-span">T</code>, if <code class="tmd-code-span">x</code> is representable as a value of type <code class="tmd-code-span">T</code>, then <code class="tmd-code-span">x</code> can be explicitly converted to <code class="tmd-code-span">T</code>. In particular if <code class="tmd-code-span">x</code> is an untyped value, then <code class="tmd-code-span">x</code> can be <span class="tmd-bold">implicitly</span> converted to <code class="tmd-code-span">T</code>.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Example:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

func main() {
	// The implicit conversions are all legal.
	const I = 123
	const I1, I2 int8 = 0x7F, -0x80
	const I3, I4 int8 = I, 0.0
	const F = 0.123456789
	const F32 float32 = F
	const F32b float32 = I
	const F64 float64 = F
	const C1, C2 complex64 = F, I
	
	// const F64b float64 = I3 // doesn't compile
	const F64b = float64(I3)   // compiles okay
	
	// const I5 int = C2 // doesn't compile
	const I5 = int(C2)   // compiles okay
}
</code></pre>
<p></p>
<h4 class="tmd-header-4">
7. non-constant number conversion rules
</h4>
<p></p>
<div class="tmd-usual well">
Non-constant floating-point and integer values can be explicitly converted to any floating-point and integer types.
</div>
<p></p>
<div class="tmd-usual well">
Non-constant complex values can be explicitly converted to any complex types.
</div>
<p></p>
<div class="tmd-usual">
Note,
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
Complex non-constant values can't be converted to floating-point and integer types.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
Floating-point and integer non-constant values can't be converted to complex types.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
Data overflow and rounding are allowed in non-constant number conversions. When converting a floating-point non-constant number to an integer, the fraction is discarded (truncation towards zero).
</div>
</li>
</ul>
<p></p>
<div class="tmd-usual">
An example:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

import "fmt"

func main() {
	var a, b = 1.6, -1.6 // both are float64
	fmt.Println(int(a), int(b)) // 1 -1

	var i, j int16 = 0x7FFF, -0x8000
	fmt.Println(int8(i), uint16(j)) // -1 32768

	var c1 complex64 = 1 + 2i
	var _ = complex128(c1)
}
</code></pre>
<p></p>
<h4 class="tmd-header-4">
8. string related conversion rules
</h4>
<p></p>
<div class="tmd-usual well">
If the type (or default type) of a value is an integer type, then the value can be explicitly converted to string types.
</div>
<p></p>
<div class="tmd-usual well">
A string value can be explicitly converted to a slice type whose underlying type is <code class="tmd-code-span">[]byte</code> (a.k.a., <code class="tmd-code-span">[]uint8</code>), and vice versa.
</div>
<p></p>
<div class="tmd-usual well">
A string value can be explicitly converted to a slice type whose underlying type is <code class="tmd-code-span">[]rune</code> (a.k.a., <code class="tmd-code-span">[]int32</code>), and vice versa.
</div>
<p></p>
<div class="tmd-usual">
Please read <a href="string.html#conversions">strings in Go</a> for details and examples.
</div>
<p></p>
<p></p>
<h4 class="tmd-header-4">
9. slices related conversions
</h4>
<p></p>
<div class="tmd-usual well">
Since Go 1.17, a slice may be converted to an array pointer. In such a conversion, if the length of the base array type of the pointer type is larger than the length of the slice, a panic occurs.
</div>
<p></p>
<div class="tmd-usual">
Here is <a href="container.html#slice-to-array-pointer">an example</a>.
</div>
<p></p>
<p></p>
<div class="tmd-usual well">
Since Go 1.20, a slice may be converted to an array. In such a conversion, if the length of the array type is larger than the length of the slice, a panic occurs.
</div>
<p></p>
<div class="tmd-usual">
Here is <a href="container.html#slice-to-array">an example</a>.
</div>
<p></p>
<p></p>
<h4 class="tmd-header-4">
10. unsafe pointers related conversion rules
</h4>
<p></p>
<div class="tmd-usual well">
A pointer value of any type can be explicitly converted to a type whose underlying type is <code class="tmd-code-span">unsafe.Pointer</code>, and vice versa.
</div>
<p></p>
<div class="tmd-usual well">
An uintptr value can be explicitly converted to a type whose underlying type is <code class="tmd-code-span">unsafe.Pointer</code>, and vice versa.
</div>
<p></p>
<div class="tmd-usual">
Please read <a href="unsafe.html">type-unsafe pointers in Go</a> for details and examples.
</div>
<p></p>
<p></p>
<h3 class="tmd-header-3">
Value Assignment Rules
</h3>
<p></p>
<div class="tmd-usual">
Assignments can be viewed as implicit conversions. Implicit conversion rules are listed among all conversion rules in the last section.
</div>
<p></p>
<div class="tmd-usual">
Besides these rules, the destination values in assignments must be addressable values, map index expressions, or the blank identifier.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
In an assignment, the source value is copied to the destination value. Precisely speaking, the <a href="value-part.html">direct part</a> of the source value is copied to the destination value.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Note, parameter passing and result returning are both value assignments actually.
</div>
<p></p>
<p></p>
<h3 id="comparison-rules" class="tmd-header-3">
Value Comparison Rules
</h3>
<p></p>
<p></p>
<div class="tmd-usual">
Go specification <a href="https://golang.org/ref/spec#Comparison_operators">states</a>:
</div>
<p></p>
<div class="tmd-usual alert alert-success">
In any comparison, the first operand must be assignable to the type of the second operand, or vice versa.
</div>
<p></p>
<div class="tmd-usual">
So, the comparison rule is much like the assignment rule. In other words, two values are comparable if one of them can be implicitly converted to the type of the other. Right? Almost, for there is another rule which has a higher priority than the above basic comparison rule.
</div>
<p></p>
<p></p>
<div class="tmd-usual alert alert-danger">
If both of the two operands in a comparison are typed, then their types must be both <a href="type-system-overview.html#types-not-support-comparison">comparable types</a>.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
By the above rule, if an incomparable type (which must be a non-interface type) implements an interface type, then it is illegal to compare values of the two types, even if values of the former (non-interface) type can be implicitly converted to the latter (interface) type.
</div>
<p></p>
<div class="tmd-usual">
Note, although values of slice/map/function types don't support comparisons, they can be compared with untyped nil values (a.k.a., bare <code class="tmd-code-span">nil</code> identifiers).
</div>
<p></p>
<div class="tmd-usual">
The above described basic rules don't cover all cases. What about if both of the two operands in a comparison are untyped (constant) values? The additional rules are simple:
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
untyped boolean values can be compared with untyped boolean values.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
untyped numeric values can be compared with untyped numeric values.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
untyped string values can be compared with untyped string values.
</div>
</li>
</ul>
<p></p>
<div class="tmd-usual">
The results of comparing two untyped numeric values obey intuition.
</div>
<p></p>
<div class="tmd-usual">
Note, an untyped nil value can't be compared with another untyped nil value.
</div>
<p></p>
<div class="tmd-usual">
Any comparison results in an untyped boolean value.
</div>
<p></p>
<div class="tmd-usual">
The following example shows some incomparable types related comparisons.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

// Some variables of incomparable types.
var s []int
var m map[int]int
var f func()()
var t struct {x []int}
var a [5]map[int]int

func main() {
	// The following lines fail to compile.
	/*
	_ = s == s
	_ = m == m
	_ = f == f
	_ = t == t
	_ = a == a
	_ = nil == nil
	_ = s == interface{}(nil)
	_ = m == interface{}(nil)
	_ = f == interface{}(nil)
	*/

	// The following lines compile okay.
	_ = s == nil
	_ = m == nil
	_ = f == nil
	_ = 123 == interface{}(nil)
	_ = true == interface{}(nil)
	_ = "abc" == interface{}(nil)
}
</code></pre>
<p></p>
<h4 id="comparison-implementation" class="tmd-header-4">
How Are Two Values Compared?
</h4>
<p></p>
<div class="tmd-usual">
Assume two values are comparable, and they have the same type <code class="tmd-code-span">T</code>. (If they have different types, one of them must be implicitly convertible to the type of the other. Here we don't consider the cases in which both the two values are untyped.)
</div>
<ol class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is a boolean type, then the two values are equal only if they are both <code class="tmd-code-span">true</code> or both <code class="tmd-code-span">false</code>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is an integer type, then the two values are equal only if they have the same representation in memory.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is a floating-point type, then the two values are equal only if any of the following conditions is satisfied:
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
they are both <code class="tmd-code-span">+Inf</code>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
they are both <code class="tmd-code-span">-Inf</code>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
each of them is either <code class="tmd-code-span">-0.0</code> or <code class="tmd-code-span">+0.0</code>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
they are both not <code class="tmd-code-span">NaN</code> and they have the same bytes representations in memory.
</div>
</li>
</ul>
<p></p>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is a complex type, then the two values are equal only if their real parts (as floating-point values) and imaginary parts (as floating-point values) are both equal.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is a pointer type (either safe or unsafe), then the two values are equal only if the memory addresses stored in them are equal.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is a channel type, the two channel values are equal if they both reference the same underlying internal channel structure value or they are both nil channels.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is a struct type, then <a href="struct.html#comparison">each pair of the corresponding fields of the two struct values will be compared</a>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is an array type, then <a href="container.html#comparison">each pair of the corresponding elements of the two array values will be compared</a>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is an interface type, please read <a href="interface.html#comparison">how two interface values are compared</a>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
If <code class="tmd-code-span">T</code> is a string type, please read <a href="string.html#comparison">how two string values are compared</a>.
</div>
</li>
</ol>
<p></p>
<p></p>
<div class="tmd-usual">
Please note, comparing two interfaces with the same incomparable dynamic type produces a panic. The following is an example in which some panics will occur in comparisons.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

func main() {
	type T struct {
		a interface{}
		b int
	}
	var x interface{} = []int{}
	var y = T{a: x}
	var z = [3]T{{a: y}}

	// Each of the following line can produce a panic.
	_ = x == x
	_ = y == y
	_ = z == z
}
</code></pre>
<p></p>
</div>
